package com.fy.service.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fy.common.constant.CmdConstants;
import com.fy.common.constant.RedisKeyConstant;
import com.fy.common.dto.ChatSessionMuteDto;
import com.fy.common.dto.ChatSessionTopDto;
import com.fy.common.entity.SkImChatSession;
import com.fy.common.entity.SkImUserInfo;
import com.fy.common.enums.SkImChatSessionEnum;
import com.fy.common.model.im.MessageModel;
import com.fy.common.util.TokenUtil;
import com.fy.dao.mapper.SkImChatSessionMapper;
import com.fy.framework.common.model.R;
import com.fy.framework.component.config.LocaleMessage;
import com.fy.framework.component.config.RedissonComponet;
import com.fy.framework.component.config.TenantContextHolder;
import com.fy.service.service.ImBrokerService;
import com.fy.service.service.SkImChatSessionService;
import com.fy.service.service.SkImUserInfoService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.redisson.api.RMapCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhshuo
 * @date 2021/12/13 11:15
 */
@Service
public class SkImChatSessionServiceImpl extends ServiceImpl<SkImChatSessionMapper, SkImChatSession> implements SkImChatSessionService {

    LocaleMessage localeMessage;

    ImBrokerService imBrokerService;

    RedissonComponet redissonComponet;

    SkImUserInfoService userInfoService;

    @Override
    public R<List<SkImChatSession>> list() {
        SkImUserInfo skImUserInfo = userInfoService.selectOne(new EntityWrapper<SkImUserInfo>().eq("sk_im_user_id", TokenUtil.getUserId()));
        RMapCache<String, Object> map = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + skImUserInfo.getSkImUserId());
        List<SkImChatSession> list = new ArrayList<>();
        if (MapUtils.isEmpty(map)) {
            list = baseMapper.list(TokenUtil.getUserId());
        } else {
            Collection<Object> values = map.values();
            for(Object o:values){
                list.add((SkImChatSession) o);
            }
        }
        list = list.stream().filter(e->e.getLastDeleteType() == null || !e.getLastDeleteType().equals(SkImChatSessionEnum.DEL.getType())).collect(Collectors.toList());
        List<SkImChatSession> topList = list.stream().filter(e->Objects.nonNull(e.getTopTime())).collect(Collectors.toList());
        List<SkImChatSession> msgList = list.stream().filter(e->Objects.isNull(e.getTopTime()) && Objects.nonNull(e.getLastMsgTime())).collect(Collectors.toList());
        List<SkImChatSession> sorted = new ArrayList<>();
        List<String> sessionIds = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(topList)){
            topList = topList.stream().sorted(Comparator.comparing(SkImChatSession::getTopTime,Comparator.reverseOrder())).collect(Collectors.toList());
            sessionIds.addAll(topList.stream().map(SkImChatSession::getSessionId).collect(Collectors.toList()));
            sorted.addAll(topList);
        }
        if(CollectionUtils.isNotEmpty(msgList)){
            msgList = msgList.stream().sorted(Comparator.comparing(SkImChatSession::getLastMsgTime,Comparator.reverseOrder())).collect(Collectors.toList());
            sessionIds.addAll(msgList.stream().map(SkImChatSession::getSessionId).collect(Collectors.toList()));
            sorted.addAll(msgList);
        }

        if(CollectionUtils.isNotEmpty(sessionIds)){
            List<SkImChatSession> collect = list.stream().filter(e -> !sessionIds.contains(e.getSessionId())).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(collect)){
                sorted.addAll(collect);
            }
        }else{
            sorted.addAll(list);
        }

        /*list = list.stream().filter(e->e.getLastDeleteType() == null || !e.getLastDeleteType().equals(SkImChatSessionEnum.DEL.getType()))
                .sorted(Comparator.comparing(SkImChatSession::getTopTime,Comparator.nullsLast(Date::compareTo)).thenComparing(SkImChatSession::getLastMsgTime,Comparator.nullsLast(Date::compareTo)))
                .collect(Collectors.toList());*/
        return R.success(sorted);
    }

    @Override
    public R<?> top(ChatSessionTopDto chatSessionId) {
        boolean top = chatSessionId.isTop();
        SkImChatSession chatSession = new SkImChatSession().setIsTop(top).setSessionId(chatSessionId.getChatSessionId());
        if (top) {
            chatSession.setTopTime(new Date());
        } else {
            chatSession.setTopTime(null);
        }
        baseMapper.updateTop(chatSession);
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + TokenUtil.getUserId());
        Object o = mapCache.get(chatSessionId.getChatSessionId());
        if (o != null) {
            SkImChatSession imChatSession = (SkImChatSession) o;
            imChatSession.setIsTop(top);
            if (top) {
                imChatSession.setTopTime(new Date());
            } else {
                imChatSession.setTopTime(null);
            }
            mapCache.put(chatSessionId.getChatSessionId(), imChatSession);
        }
        MessageModel messageModel = new MessageModel();
        messageModel.setFrom(TokenUtil.getUserId());
        messageModel.setDeviceCode(TokenUtil.getParamsFromToken("device", String.class));
        messageModel.setTenantId(TenantContextHolder.getTenant());
        messageModel.setCmd(CmdConstants.RESPONSE_SESSION_TOP);
        imBrokerService.sendToMyOtherDevice(messageModel);
        return R.success(localeMessage.getMessage("im.common.successful"));
    }

    @Override
    public R<?> mute(ChatSessionMuteDto sessionMuteDto) {
        boolean mute = sessionMuteDto.isMute();
        SkImChatSession chatSession = new SkImChatSession().setIsMute(mute);
        update(chatSession, new EntityWrapper<SkImChatSession>().eq("session_id", sessionMuteDto.getChatSessionId()));
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + TokenUtil.getUserId());
        Object o = mapCache.get(sessionMuteDto.getChatSessionId());
        if (o != null) {
            SkImChatSession imChatSession = (SkImChatSession) o;
            imChatSession.setIsMute(mute);
            mapCache.put(sessionMuteDto.getChatSessionId(), imChatSession);
        }
        MessageModel messageModel = new MessageModel();
        messageModel.setFrom(TokenUtil.getUserId());
        messageModel.setDeviceCode(TokenUtil.getParamsFromToken("device", String.class));
        messageModel.setTenantId(TenantContextHolder.getTenant());
        messageModel.setCmd(CmdConstants.RESPONSE_MUTE);
        imBrokerService.sendToMyOtherDevice(messageModel);
        return R.success(localeMessage.getMessage("im.common.successful"));
    }

    @Override
    public void del(String chatSessionId) {
        Date date = new Date();
        update(new SkImChatSession().setLastDeleteTime(date).setLastDeleteType(SkImChatSessionEnum.DEL.getType()),new EntityWrapper<SkImChatSession>().eq("session_id",chatSessionId));
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + TokenUtil.getUserId());
        redissonComponet.delteMapKey(RedisKeyConstant.USER_CHAT_SESSION + TokenUtil.getUserId(),chatSessionId);
    }

    @Override
    public void clear(String chatSessionId) {
        SkImChatSession chatSession = selectOne(new EntityWrapper<SkImChatSession>().eq("session_id", chatSessionId));
        SkImChatSession chatSessionOther = selectOne(new EntityWrapper<SkImChatSession>().eq("sk_im_user_id", chatSession.getTargetId()).eq("target_id",chatSession.getSkImUserId()));
        Date date = new Date();
        update(new SkImChatSession().setLastDeleteTime(date).setLastDeleteType(SkImChatSessionEnum.CLEAR.getType()),new EntityWrapper<SkImChatSession>().eq("id",chatSession.getId()));
        update(new SkImChatSession().setLastDeleteTime(date).setLastDeleteType(SkImChatSessionEnum.CLEAR.getType()),new EntityWrapper<SkImChatSession>().eq("id",chatSessionOther.getId()));
        RMapCache<String, Object> mapCache = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + chatSession.getSkImUserId());
        Object o = mapCache.get(chatSession.getSessionId());
        if (o != null) {
            SkImChatSession imChatSession = (SkImChatSession) o;
            imChatSession.setLastDeleteTime(date).setLastDeleteType(SkImChatSessionEnum.CLEAR.getType());
            mapCache.put(chatSession.getSessionId(), imChatSession);
        }
        RMapCache<String, Object> mapOther = redissonComponet.getMap(RedisKeyConstant.USER_CHAT_SESSION + chatSessionOther.getSkImUserId());
        Object map = mapOther.get(chatSessionOther.getSessionId());
        if (map != null) {
            SkImChatSession imChatSession = (SkImChatSession) map;
            imChatSession.setLastDeleteTime(date).setLastDeleteType(SkImChatSessionEnum.CLEAR.getType());
            mapOther.put(chatSessionOther.getSessionId(), imChatSession);
        }
    }

    @Override
    public void topOrMuteSet(SkImChatSession chatSession) {
        baseMapper.topOrMuteSet(chatSession);
    }

    @Autowired
    public void setLocaleMessage(LocaleMessage localeMessage) {
        this.localeMessage = localeMessage;
    }

    @Autowired
    public void setImBrokerService(ImBrokerService imBrokerService) {
        this.imBrokerService = imBrokerService;
    }

    @Autowired
    public void setRedissonComponet(RedissonComponet redissonComponet) {
        this.redissonComponet = redissonComponet;
    }

    @Autowired
    public void setUserInfoService(SkImUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }
}